home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 19
/
Mac Magazin and MacEasy Magazine CD - Issue 19.iso
/
Musik & Kunst
/
Ear Workout 2.1
/
source code
/
ear_main.cp
< prev
next >
Wrap
Text File
|
1996-01-15
|
17KB
|
690 lines
//
// Ear Workout, by Ben Crowell
//
// Version history:
// version 1.0 - 21 Nov 95
// Includes two workouts: chords and intervals.
// version 2.0 - 9 Jan 96
// New workout: singing intervals (currently works ok
// with whistling, but not as well with singing).
//
// Ideas for new workouts:
// Play scale, play chord, they identify chord w.r.t. key.
// Rhythm: reading? rhythmic canons? cross-rhythms?
// Tetrachords; identify by mac-style click and select
// across the scale
// Identify inversions of chords.
//
// Improvements to make:
// Staff notation could look a lot better.
// Misc possible improvements in chords: see ear_chords.cp
// Should store waveforms in a resource, instead of computing them
// when we start up.
// Implementation of volume control is not so great: should
// highlight the previous volume selection.
// Timbre of synthesized notes is not exactly beautiful.
// Subroutine bail_out() should give a dialog box, not just write to a file.
//
// Bugs:
// If it's already running (no workout open), and you double-click
// on it in the finder, you get a watch cursor that never changes
// to an arrow. Also may crash.
//
//
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <OSUtils.h>
#include <QuickDraw.h>
#include <Sound.h>
#define NEED_MAC_STUFF 1
#include "Ninkasi:C++ util:generic.h"
#include "Ninkasi:C++ util:complete_window.h"
#include "ear_defines.h"
#include "ear_globals.h"
#include "ear_prototypes.h"
void init_mac_stuff();
void wrap_it_up();
void set_up_menus(int resource_id,int apple_menu_id);
void event_loop();
void do_mouse_down(EventRecord *my_event);
void do_controls(WindowPtr window,Point where,EventRecord *my_event);
void do_menu(long command);
typedef pascal void (*track_control_filter_ptr_t)(ControlRecord**,short);
Rect drag_rect;
void make_intervals_window();
void make_chord_window();
void make_about_ear_training_window();
void make_sing_interval_window();
DEN_MOTHER_T interval_den_mother,chord_den_mother,about_ear_training_den_mother,
chord_help_den_mother,about_chord_den_mother,sing_interval_den_mother;
int which_complete_window(WindowPtr w);
void do_update(EventRecord *my_event);
void do_activate(EventRecord *my_event);
void do_key(EventRecord *my_event);
void select_initial_workout();
//-------------------------------------------------------------
void
main()
{
init_mac_stuff();
set_up_menus(MBAR_ID,APPLE_MENU_ID);
watch_cursor();
set_up_sound();
arrow_cursor();
normal_text_style();
select_initial_workout();
event_loop();
//--should never drop through here, but just in case:
wrap_it_up();
}
//... called at beginning of progra; can also be called later
// to reinstall everything (without recalculating wave table
void
set_up_sound()
{
do_waveforms(my_snd_chan,4,0.15,chans_used,my_wave_table,
temp_wave_table,WAVE_TABLE_SIZE);
}
void
select_initial_workout()
{
DialogPtr my_dialog;
short item_hit;
my_dialog = GetNewDialog(SELECT_INITIAL_WORKOUT_MODAL_DLOG_ID,
0,(WindowPtr) -1);
if (VALID_POINTER(my_dialog)) {
ModalDialog(0,&item_hit);
DisposDialog(my_dialog);
switch(item_hit) {
case 1: //-- chords
make_chord_window();
break;
case 2: //-- intervals
make_intervals_window();
break;
case 4: //-- no workout
break;
case 5: //-- quit
wrap_it_up();
break;
case 6: //-- sing intervals
make_sing_interval_window();
break;
}
}
}
void
set_volume()
{
DialogPtr my_dialog;
short item_hit;
short vol,z;
int i;
int get_current_volume(SndChannelPtr snd_chan);
void set_volume(int new_volume,SndChannelPtr snd_chan);
my_dialog = GetNewDialog(VOLUME_MODAL_DLOG_ID,
0,(WindowPtr) -1);
/*
vol = 7 & ((GetSysPPtr()->volClik)>>8);
*/
vol = 0;
vol = get_current_volume(my_snd_chan[0])/(512/8)-1;
if (vol>=1 && vol<=7) SetDialogDefaultItem(my_dialog,(short) vol);
if (VALID_POINTER(my_dialog)) {
ModalDialog(0,&item_hit);
DisposDialog(my_dialog);
switch(item_hit) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
vol = item_hit;
#if 0
z = GetSysPPtr()->volClik;
z = (z & 0xf8ff) | (vol<<8);
dispose_of_chans(chans_used,my_snd_chan);
GetSysPPtr()->volClik = z;
WriteParam(); //...cf InitUtil
InitUtil();
set_up_sound();
#endif
#if 1
// The above stuff with the system parameter block didn't
// work. Apparently there is some magic way of notifying
// the os that you've changed the volume, but I can't figure
// out what it is. Instead, force it to recalculate the
// waveform, which is time-consuming:
have_wave_table = 0;
do_waveforms(my_snd_chan,4,0.15*vol/7.,chans_used,my_wave_table,
temp_wave_table,WAVE_TABLE_SIZE);
#endif
// Doesn't work:
#if 0
for (i=0; i<chans_used; i++)
set_volume(vol,my_snd_chan[i]);
#endif
break;
case 8:
break;
}
}
}
void
wrap_it_up()
{
int i;
for (i=0; i<n_windows; i++) {
delete my_windows[i];
}
dispose_of_chans(chans_used,my_snd_chan);
if (have_sample_storage) {
if (VALID_HANDLE(sound_handle)) DisposHandle(sound_handle);
have_sample_storage = 0;
}
ExitToShell();
}
void
init_mac_stuff()
{
InitGraf(&thePort);
init_random(); /* must do InitGraf first!!!!!! */
InitFonts();
FlushEvents(everyEvent,0);
InitWindows();
InitMenus();
InitCursor();
//if (OpenResFile("\pmy.rsrc") == -1)
// bail_out("could not open resource file");
resources_available = 1;
drag_rect = thePort->portRect;
TextSize((short) normal_font_size);
TEInit();
}
void
make_window(int dlog_resource_id,
Str255 param_text0,
Str255 param_text1,
Str255 param_text2,
Str255 param_text3,
DEN_MOTHER_T *den_mother)
{
if (n_windows>=MAX_WINDOWS) return;
++n_windows;
my_windows[n_windows-1] = new complete_window(dlog_resource_id,
param_text0,param_text1,param_text2,param_text3,
den_mother);
if (!VALID_POINTER(my_windows[n_windows-1])
|| !my_windows[n_windows-1]->is_valid) {
--n_windows;
}
}
void
remove_window(int which)
{
int i;
if (which>=n_windows) return;
if (VALID_POINTER(my_windows[which])) {
delete my_windows[which];
//-- destructor will call the den mother and
// do a DisposDialog
for (i=which; i<=n_windows-2; i++) {
my_windows[i] = my_windows[i+1];
}
}
--n_windows;
}
int
which_complete_window(WindowPtr w)
{
int i;
for (i=0; i<n_windows; i++) {
if (my_windows[i]->the_window==w) return i;
}
return -1;
}
void
event_loop()
{
EventRecord my_event;
int valid;
for (;;) {
SystemTask();
valid = GetNextEvent(everyEvent,&my_event);
if (valid) {
switch(my_event.what) {
case keyDown:
do_key(&my_event);
break;
case mouseDown:
do_mouse_down(&my_event);
break;
case activateEvt:
do_activate(&my_event);
break;
case updateEvt:
do_update(&my_event);
break;
default:
break;
} //-- end switch
} //-- end if valid
} //-- end for (;;)
}
void
do_key(EventRecord *my_event)
{
long menu_result;
int is_menu;
is_menu = 0;
if ((my_event->modifiers & cmdKey)!=0) {
menu_result = MenuKey((char) (my_event->message & charCodeMask));
is_menu = (HiWord(menu_result)!=0);
}
if (is_menu) {
do_menu(menu_result);
}
else {
//-- handle keystrokes
}
}
void
do_update(EventRecord *my_event)
{
GrafPtr save_graf;
WindowPtr window;
int which;
complete_window *the_complete_window;
window = (WindowPtr) my_event->message;
which = which_complete_window(window);
if (which>=0) {
GetPort(&save_graf);
SetPort(window);
BeginUpdate(window);
EraseRect(&window->portRect);
DrawControls(window);
the_complete_window = my_windows[which];
the_complete_window->whassup = complete_window_redraw;
the_complete_window->the_event = my_event;
(*(the_complete_window->den_mother))(the_complete_window);
EndUpdate(window);
SetPort(save_graf);
}
}
void
do_activate(EventRecord *my_event)
{
if (my_event->modifiers & 1)
SetPort((WindowPtr) (my_event->message)); //--activate event
else
; //--deactivate event
}
//------- watch out that memory doesn't move, orphaning mouse_window
void
do_mouse_down(EventRecord *my_event)
{
WindowPtr mouse_window;
int which_part;
which_part = FindWindow(my_event->where,&mouse_window);
switch(which_part) {
case inMenuBar:
do_menu(MenuSelect(my_event->where));
break;
case inSysWindow:
SystemClick(my_event,mouse_window);
break;
case inGoAway:
{
int which;
complete_window *the_complete_window;
which = which_complete_window(mouse_window);
if (which != -1) {
remove_window(which);
}
}
break;
case inContent:
if (mouse_window != FrontWindow())
SelectWindow(mouse_window);
else
do_controls(mouse_window,my_event->where,my_event);
break;
case inDrag:
DragWindow(mouse_window,my_event->where,&drag_rect);
break;
default:
break;
}
}
void
do_menu(long command)
{
int menu_id,item;
menu_id = HiWord(command);
item = LoWord(command);
switch(menu_id) {
case APPLE_MENU_ID:
{
unsigned char item_name[32];
switch(item) {
case 1:
//-- about Ear Training
make_about_ear_training_window();
break;
default:
GetItem(GetMHandle((short) menu_id),(short) item,item_name);
OpenDeskAcc(item_name);
break;
}
}
break;
case FILE_MENU_ID:
ExitToShell();
break;
case EDIT_MENU_ID:
if (item<=6 && item!=2) {
int which;
if (!SystemEdit(item-1)) {
//...returns 0 if we should handle it
which = which_complete_window(FrontWindow());
if (which != -1) {
message_to_den_mother(my_windows[which],
(void **) 0,(void *) 0,(int) item,"edit");
}
}
}
break;
case WORKOUTS_MENU_ID:
switch(item) {
case 1:
make_intervals_window();
break;
case 2:
make_chord_window();
break;
case 3:
make_sing_interval_window();
break;
}
break;
case OPTIONS_MENU_ID:
switch(item) {
case 1: //-- volume
set_volume();
break;
}
}
HiliteMenu(0);
}
void
do_controls(WindowPtr window,Point where,EventRecord *my_event)
{
int which;
complete_window *the_complete_window;
ControlHandle control;
which = which_complete_window(window);
if (which== -1) bail_out("unknown window in do_controls");
the_complete_window = my_windows[which];
if (!VALID_POINTER(the_complete_window)
|| !the_complete_window->is_valid
|| !VALID_POINTER(the_complete_window->den_mother))
bail_out("window is garbage in do_controls");
GlobalToLocal(&where);
//---this assumes that the routine do_activate
// has set the graf port to be _this_ window
the_complete_window->part_code = FindControl(where,window,&control);
if (!TrackControl(control,where,(track_control_filter_ptr_t) 0)) return;
if (!the_complete_window->part_code) return;
the_complete_window->part_number
= FindDItem(window,where);
if (the_complete_window->part_number == -1) return;
the_complete_window->whassup = complete_window_action;
the_complete_window->the_event = my_event;
(*(the_complete_window->den_mother))(the_complete_window);
}
void
make_chord_help_window()
{
if (!chord_help_window_exists) {
make_window(CHORD_HELP_DLOG_ID,"\p","\p","\p","\p",
&chord_help_den_mother);
chord_help_window_exists = 1;
}
}
void
make_about_ear_training_window()
{
if (!about_ear_training_window_exists) {
make_window(ABOUT_EAR_TRAINING_DLOG_ID,"\p","\p","\p","\p",
&about_ear_training_den_mother);
about_ear_training_window_exists = 1;
}
}
void
make_intervals_window()
{
if (!interval_window_exists) {
make_window(INTERVAL_DLOG_ID,"\p","\p","\p","\p",
&interval_den_mother);
interval_window_exists = 1;
}
}
void
make_sing_interval_window()
{
if (!sing_interval_window_exists) {
make_window(SING_INTERVAL_DLOG_ID,"\p","\p","\p","\p",
&sing_interval_den_mother);
sing_interval_window_exists = 1;
}
}
void
make_chord_window()
{
if (!chord_window_exists) {
make_window(CHORD_DLOG_ID,"\p","\p","\p","\p",
&chord_den_mother);
chord_window_exists = 1;
}
}
// should check if resources_available, and if so, use dialog box
void
bail_out(char *message)
{
SysBeep((short) 0);
debug_print(message);
wrap_it_up();
}
void
set_up_menus(int resource_id,int apple_menu_id)
{
Handle mbar_handle;
MenuHandle apple_menu;
mbar_handle = GetNewMBar((short) resource_id);
if (ResError()!=0 || !VALID_HANDLE(mbar_handle) )
bail_out("error reading menu bar");
SetMenuBar(mbar_handle);
apple_menu = GetMHandle((short) apple_menu_id);
if (!VALID_HANDLE(apple_menu) )
bail_out("error getting apple menu");
AddResMenu(apple_menu,'DRVR');
DrawMenuBar();
}
void
about_ear_training_den_mother(complete_window *my_complete_window)
{
int need_to_redraw,ready_to_update;
GrafPtr save_graf;
need_to_redraw = 0;
ready_to_update = 0;
switch(my_complete_window->whassup) {
case complete_window_created:
need_to_redraw = 1;
break;
case complete_window_redraw:
need_to_redraw = 1;
ready_to_update = 1; //-- main program does begin update & sets graf port
break;
case complete_window_action:
break;
case complete_window_erase:
about_ear_training_window_exists = 0;
return;
}
if (need_to_redraw) {
if (!ready_to_update) {
GetPort(&save_graf);
SetPort(my_complete_window->the_window);
}
{
short tt;
Handle hh;
Rect rr;
unsigned char s[300];
TextFont((short) newYork);
GetDItem(my_complete_window->the_window,(short) 1,&tt,&hh,&rr);
if (VALID_HANDLE(hh)) {
GetIText(hh,s);
SetIText(hh,s);
}
GetDItem(my_complete_window->the_window,(short) 2,&tt,&hh,&rr);
if (VALID_HANDLE(hh)) {
GetIText(hh,s);
SetIText(hh,s);
}
TextSize((short) 10);
GetDItem(my_complete_window->the_window,(short) 3,&tt,&hh,&rr);
if (VALID_HANDLE(hh)) {
GetIText(hh,s);
SetIText(hh,s);
}
normal_text_style();
}
if (!ready_to_update) {
SetPort(save_graf);
}
}//---end if need to redraw
}
void
chord_help_den_mother(complete_window *my_complete_window)
{
int need_to_redraw,ready_to_update;
GrafPtr save_graf;
need_to_redraw = 0;
ready_to_update = 0;
switch(my_complete_window->whassup) {
case complete_window_created:
need_to_redraw = 1;
break;
case complete_window_redraw:
need_to_redraw = 1;
ready_to_update = 1; //-- main program does begin update & sets graf port
break;
case complete_window_action:
break;
case complete_window_erase:
chord_help_window_exists = 0;
return;
}
if (need_to_redraw) {
if (!ready_to_update) {
GetPort(&save_graf);
SetPort(my_complete_window->the_window);
}
TextFont((short) geneva);
{
int i;
short tt;
Handle hh;
Rect rr;
unsigned char s[300];
for (i=1; i<=7; i++) {
GetDItem(my_complete_window->the_window,(short) i,&tt,&hh,&rr);
if (VALID_HANDLE(hh)) {
GetIText(hh,s);
SetIText(hh,s);
}
}
}
normal_text_style();
if (!ready_to_update) {
SetPort(save_graf);
}
}//---end if need to redraw
}